package ${buildCodeRequest.codePackageDTO.basePackage}.biz.impl;

import org.web.base.domain.ResultDO;
import ${buildCodeRequest.codePackageDTO.getDtoPackage()}.${buildCodeRequest.codeClassNameDTO.getDtoClassName()};
import ${buildCodeRequest.codePackageDTO.queryDTOPackage}.${buildCodeRequest.codeClassNameDTO.queryDTOClassName};
import ${buildCodeRequest.codePackageDTO.servicePackage}.${buildCodeRequest.codeClassNameDTO.getServiceClassName()};

import java.util.*;

import org.springframework.stereotype.Service;
import org.springframework.beans.BeanUtils;

<#if buildCodeRequest.jdkVersion != '1.8' && buildCodeRequest.jdkVersion != '8'>
import jakarta.annotation.Resource;
<#else>
import javax.annotation.Resource;
</#if>

import org.apache.log4j.Logger;
import ${buildCodeRequest.codePackageDTO.bizPackage}.${buildCodeRequest.codeClassNameDTO.bizClassName};
import ${buildCodeRequest.codePackageDTO.queryPackage}.${buildCodeRequest.codeClassNameDTO.queryClassName};
import ${buildCodeRequest.codePackageDTO.getDomainPackage()}.${buildCodeRequest.codeClassNameDTO.getDomainClassName()};
import org.web.base.domain.exception.ResultMessageEnum;
import org.web.base.domain.helper.*;
import org.apache.commons.lang3.StringUtils;

import java.util.stream.Collectors;
import java.util.List;

@Service("${buildCodeRequest.codeClassNameDTO.getBizObjectName()}")
public class ${buildCodeRequest.codeClassNameDTO.bizClassName}Impl implements ${buildCodeRequest.codeClassNameDTO.bizClassName} {

    private final Logger logger = Logger.getLogger(${buildCodeRequest.codeClassNameDTO.bizClassName}Impl.class);

    @Resource
    private ${buildCodeRequest.codeClassNameDTO.getServiceClassName()} ${buildCodeRequest.codeClassNameDTO.getServiceObjectName()};

    @Override
    public ResultDO<List<${buildCodeRequest.codeClassNameDTO.getDtoClassName()}>> ${buildCodeRequest.codeMethodDTO.queryListMethod}(${buildCodeRequest.codeClassNameDTO.queryDTOClassName} ${buildCodeRequest.codeClassNameDTO.queryDTOObjectName}) {
        ResultDO<List<${buildCodeRequest.codeClassNameDTO.getDtoClassName()}>> resultDO = new ResultDO<>();
        try {
            if (${buildCodeRequest.codeClassNameDTO.queryDTOObjectName} == null) {
                throw ServiceExceptionHelper.buildServiceException(ResultMessageEnum.PARAM_EMPTY);
            }
            ${buildCodeRequest.codeClassNameDTO.queryDTOObjectName}.checkAndBuildQuery();
            ValidationHelper.validateWithThrow(${buildCodeRequest.codeClassNameDTO.queryDTOClassName}.class, ${buildCodeRequest.codeClassNameDTO.queryDTOObjectName});
            ${buildCodeRequest.codeClassNameDTO.queryClassName} ${buildCodeRequest.codeClassNameDTO.queryObjectName} = new ${buildCodeRequest.codeClassNameDTO.queryClassName}();
            BeanUtils.copyProperties(${buildCodeRequest.codeClassNameDTO.queryDTOObjectName}, ${buildCodeRequest.codeClassNameDTO.queryObjectName});
            List<${buildCodeRequest.codeClassNameDTO.getDomainClassName()}> selectList = ${buildCodeRequest.codeClassNameDTO.getServiceObjectName()}.${buildCodeRequest.codeMethodDTO.queryListMethod}(${buildCodeRequest.codeClassNameDTO.queryObjectName});
            List<${buildCodeRequest.codeClassNameDTO.getDtoClassName()}> list = new ArrayList<>();
            resultDO.setDomain(list);
            for (${buildCodeRequest.codeClassNameDTO.getDomainClassName()} ${buildCodeRequest.codeClassNameDTO.getDomainObjectName()} : selectList) {
                ${buildCodeRequest.codeClassNameDTO.getDtoClassName()} ${buildCodeRequest.codeClassNameDTO.getDtoObjectName()} = new ${buildCodeRequest.codeClassNameDTO.getDtoClassName()}();
                BeanUtils.copyProperties(${buildCodeRequest.codeClassNameDTO.getDomainObjectName()}, ${buildCodeRequest.codeClassNameDTO.getDtoObjectName()});
                list.add(${buildCodeRequest.codeClassNameDTO.getDtoObjectName()});
            }
        } catch (Exception e) {
            logger.error(ServiceExceptionHelper.getExceptionInfo(e));
            return ResultHelper.buildResultDOByException(e);
        }
        return resultDO;
    }

    @Override
    public ResultDO<Integer> ${buildCodeRequest.codeMethodDTO.countMethod}(${buildCodeRequest.codeClassNameDTO.queryDTOClassName} ${buildCodeRequest.codeClassNameDTO.queryDTOObjectName}) {
        ResultDO<Integer> resultDO = new ResultDO<>();
        try {
            if (${buildCodeRequest.codeClassNameDTO.queryDTOObjectName} == null) {
                throw ServiceExceptionHelper.buildServiceException(ResultMessageEnum.PARAM_EMPTY);
            }
            ValidationHelper.validateWithThrow(${buildCodeRequest.codeClassNameDTO.queryDTOClassName}.class, ${buildCodeRequest.codeClassNameDTO.queryDTOObjectName});
            ${buildCodeRequest.codeClassNameDTO.queryClassName} ${buildCodeRequest.codeClassNameDTO.queryObjectName} = new ${buildCodeRequest.codeClassNameDTO.queryClassName}();
            BeanUtils.copyProperties(${buildCodeRequest.codeClassNameDTO.queryObjectName}, ${buildCodeRequest.codeClassNameDTO.queryDTOObjectName});
            Integer count = ${buildCodeRequest.codeClassNameDTO.getServiceObjectName()}.${buildCodeRequest.codeMethodDTO.countMethod}(${buildCodeRequest.codeClassNameDTO.queryObjectName});
            resultDO.setDomain(count);
        } catch (Exception e) {
            logger.error(ServiceExceptionHelper.getExceptionInfo(e));
            return ResultHelper.buildResultDOByException(e);
        }
        return resultDO;
    }

    @Override
    public ResultDO<List<${buildCodeRequest.codeClassNameDTO.getDtoClassName()}>> ${buildCodeRequest.codeMethodDTO.batchSaveListMethod}(List<${buildCodeRequest.codeClassNameDTO.getDtoClassName()}> list) {
        ResultDO<List<${buildCodeRequest.codeClassNameDTO.getDtoClassName()}>> resultDO = new ResultDO<>(true);
        try {
            resultDO.setDomain(list);
            if (list == null || list.isEmpty()) {
                throw ServiceExceptionHelper.buildServiceException(ResultMessageEnum.PARAM_EMPTY);
            }
            List<String> uniqueList = new ArrayList<>();
            List<${buildCodeRequest.codeClassNameDTO.getDtoClassName()}> insertList = new LinkedList<>();
            List<${buildCodeRequest.codeClassNameDTO.getDtoClassName()}> updateList = new LinkedList<>();
            List<Integer> primaryKeyList = new ArrayList<>();
            for (${buildCodeRequest.codeClassNameDTO.getDtoClassName()} ${buildCodeRequest.codeClassNameDTO.getDtoObjectName()} : list) {
                if (${buildCodeRequest.codeClassNameDTO.getDtoObjectName()}.${buildCodeRequest.primaryAttributeDTO.javaAttribute.getAttributeGetMethodName()}() == null) {
                    insertList.add(${buildCodeRequest.codeClassNameDTO.getDtoObjectName()});
                } else {
                    primaryKeyList.add(${buildCodeRequest.codeClassNameDTO.getDtoObjectName()}.${buildCodeRequest.primaryAttributeDTO.javaAttribute.getAttributeGetMethodName()}());
                    updateList.add(${buildCodeRequest.codeClassNameDTO.getDtoObjectName()});
                }
                if (StringUtils.isNotBlank(${buildCodeRequest.codeClassNameDTO.getDtoObjectName()}.getUserMail())) {
                    uniqueList.add(${buildCodeRequest.codeClassNameDTO.getDtoObjectName()}.getUserMail());
                }
            }

            // 校验主键是否存在重复
            String duplicatesInfo = ListHelper.findDuplicatesByToString(primaryKeyList, ",");
            if (StringUtils.isNotBlank(duplicatesInfo)) {
                throw ServiceExceptionHelper.buildServiceException(ResultMessageEnum.PARAM_INVALID, "主键重复,重复主键：" + duplicatesInfo);
            }

            // 校验唯一性是否存在重复
            duplicatesInfo = ListHelper.findDuplicatesByToString(uniqueList, ",");
            if (StringUtils.isNotBlank(ListHelper.findDuplicatesByToString(uniqueList, ","))) {
                throw ServiceExceptionHelper.buildServiceException(ResultMessageEnum.PARAM_INVALID, "唯一性重复,重复信息：" + duplicatesInfo);
            }

            // 根据唯一性，从数据库判断是否存在重复数据，如果存在，则进行更新操作。
            List<${buildCodeRequest.codeClassNameDTO.getDtoClassName()}> updateListFromInsertList = new ArrayList<>();
            for (${buildCodeRequest.codeClassNameDTO.getDtoClassName()} ${buildCodeRequest.codeClassNameDTO.getDtoObjectName()} : insertList) {
                // 基于唯一性判断是否存在重复数据。
                ${buildCodeRequest.codeClassNameDTO.queryClassName} ${buildCodeRequest.codeClassNameDTO.queryObjectName} = new ${buildCodeRequest.codeClassNameDTO.queryClassName}();
                ${buildCodeRequest.codeClassNameDTO.queryObjectName}.setUserMail(${buildCodeRequest.codeClassNameDTO.getDtoObjectName()}.getUserMail());
                ${buildCodeRequest.codeClassNameDTO.getDomainClassName()} selectOne${buildCodeRequest.codeMethodDTO.tableJavaAttributeName} = ${buildCodeRequest.codeClassNameDTO.getServiceObjectName()}.selectOne${buildCodeRequest.codeMethodDTO.tableJavaAttributeName}(${buildCodeRequest.codeClassNameDTO.queryObjectName});
                if (selectOne${buildCodeRequest.codeMethodDTO.tableJavaAttributeName} != null) {
                    ${buildCodeRequest.codeClassNameDTO.getDtoObjectName()}.${buildCodeRequest.primaryAttributeDTO.javaAttribute.getAttributeSetMethodName()}(selectOne${buildCodeRequest.codeMethodDTO.tableJavaAttributeName}.${buildCodeRequest.primaryAttributeDTO.javaAttribute.getAttributeGetMethodName()}());
                    updateListFromInsertList.add(${buildCodeRequest.codeClassNameDTO.getDtoObjectName()});
                }
            }

            // 校验更新数据是否存在重复
            if (!updateList.isEmpty()) {
                // 1. 提取待更新的所有主键ID
                Set<Integer> primaryKeySet = updateList.stream()
                        .map(${buildCodeRequest.codeClassNameDTO.getDtoClassName()}::${buildCodeRequest.primaryAttributeDTO.javaAttribute.getAttributeGetMethodName()})
                        .collect(Collectors.toSet());

                // 2. 查询数据库中实际存在的主键ID
                ${buildCodeRequest.codeClassNameDTO.queryClassName} ${buildCodeRequest.codeClassNameDTO.queryObjectName} = new ${buildCodeRequest.codeClassNameDTO.queryClassName}();
                ${buildCodeRequest.codeClassNameDTO.queryObjectName}.setAllRecords();
                ${buildCodeRequest.codeClassNameDTO.queryObjectName}.setSpecifiedAttributeSet(new HashSet<>(List.of("user_info_id")));
                ${buildCodeRequest.codeClassNameDTO.queryObjectName}.${buildCodeRequest.primaryAttributeDTO.javaAttribute.getAttributeSetMethodName()}Set(primaryKeySet);
                List<${buildCodeRequest.codeClassNameDTO.getDomainClassName()}> selectList = ${buildCodeRequest.codeClassNameDTO.getServiceObjectName()}.${buildCodeRequest.codeMethodDTO.queryListMethod}(${buildCodeRequest.codeClassNameDTO.queryObjectName});

                // 3. 提取数据库中存在的ID
                Set<Integer> existIds = selectList.stream()
                        .map(${buildCodeRequest.codeClassNameDTO.getDomainClassName()}::${buildCodeRequest.primaryAttributeDTO.javaAttribute.getAttributeGetMethodName()})
                        .collect(Collectors.toSet());

                // 4. 找出待更新ID中不存在的ID
                Set<Integer> notExistIds = primaryKeySet.stream()
                        .filter(id -> !existIds.contains(id))
                        .collect(Collectors.toSet());

                // 5. 若存在不存在的ID，抛出异常并列出具体ID
                if (!notExistIds.isEmpty()) {
                    throw ServiceExceptionHelper.buildServiceException(
                            ResultMessageEnum.PARAM_INVALID,
                            "更新失败：以下主键ID不存在于数据库中：" + notExistIds.stream().map(String::valueOf).collect(Collectors.joining(", "))
                    );
                }
            }

            // 从insertList中移除updateListFromInsertList
            if (!updateListFromInsertList.isEmpty()) {
                for (${buildCodeRequest.codeClassNameDTO.getDtoClassName()} ${buildCodeRequest.codeClassNameDTO.getDtoObjectName()} : updateListFromInsertList) {
                    updateList.add(${buildCodeRequest.codeClassNameDTO.getDtoObjectName()});
                    insertList.remove(${buildCodeRequest.codeClassNameDTO.getDtoObjectName()});
                }
            }

            if (!insertList.isEmpty()) {
                List<${buildCodeRequest.codeClassNameDTO.getDomainClassName()}> insertListForDomain = new ArrayList<>();
                for (${buildCodeRequest.codeClassNameDTO.getDtoClassName()} ${buildCodeRequest.codeClassNameDTO.getDtoObjectName()} : insertList) {
                    ${buildCodeRequest.codeClassNameDTO.getDomainClassName()} insert${buildCodeRequest.codeClassNameDTO.getDomainClassName()} = new ${buildCodeRequest.codeClassNameDTO.getDomainClassName()}();
                    BeanUtils.copyProperties(${buildCodeRequest.codeClassNameDTO.getDtoObjectName()}, insert${buildCodeRequest.codeClassNameDTO.getDomainClassName()});
<#list buildCodeRequest.attributeDTOList as attributeDTO>
<#if attributeDTO.javaAttribute.javaAttributeExtendDTO?? 
    && attributeDTO.javaAttribute.javaAttributeExtendDTO.initDefaultValue?has_content>
                    if (StringUtils.isBlank(${buildCodeRequest.codeClassNameDTO.getDtoObjectName()}.${attributeDTO.javaAttribute.getAttributeGetMethodName()}())) {
                        insert${buildCodeRequest.codeClassNameDTO.getDomainClassName()}.${attributeDTO.javaAttribute.getAttributeSetMethod()}(${buildCodeRequest.codeClassNameDTO.getDtoClassName()}.${attributeDTO.columnAttribute.upperColumnName}_DEFAULT_VALUE);
                        ${buildCodeRequest.codeClassNameDTO.getDtoObjectName()}.${attributeDTO.javaAttribute.getAttributeSetMethod()}(${buildCodeRequest.codeClassNameDTO.getDtoClassName()}.${attributeDTO.columnAttribute.upperColumnName}_DEFAULT_VALUE);
                    }
</#if>
</#list>
                    insertListForDomain.add(insert${buildCodeRequest.codeClassNameDTO.getDomainClassName()});
                }
                List<${buildCodeRequest.codeClassNameDTO.getDomainClassName()}> insertRecords = ${buildCodeRequest.codeClassNameDTO.getServiceObjectName()}.${buildCodeRequest.codeMethodDTO.batchInsertMethod}(insertListForDomain);
                Map<String, ${buildCodeRequest.codeClassNameDTO.getDomainClassName()}> insertMap = new HashMap<>();
                for (${buildCodeRequest.codeClassNameDTO.getDomainClassName()} ${buildCodeRequest.codeClassNameDTO.getDomainObjectName()} : insertRecords) {
                    insertMap.put(${buildCodeRequest.codeClassNameDTO.getDomainObjectName()}.getUserMail(), ${buildCodeRequest.codeClassNameDTO.getDomainObjectName()});
                }
                for (${buildCodeRequest.codeClassNameDTO.getDtoClassName()} ${buildCodeRequest.codeClassNameDTO.getDtoObjectName()} : insertList) {
                    ${buildCodeRequest.codeClassNameDTO.getDomainClassName()} ${buildCodeRequest.codeClassNameDTO.getDomainObjectName()} = insertMap.get(${buildCodeRequest.codeClassNameDTO.getDtoObjectName()}.getUserMail());
                    ${buildCodeRequest.codeClassNameDTO.getDtoObjectName()}.${buildCodeRequest.primaryAttributeDTO.javaAttribute.getAttributeSetMethodName()}(${buildCodeRequest.codeClassNameDTO.getDomainObjectName()}.${buildCodeRequest.primaryAttributeDTO.javaAttribute.getAttributeGetMethodName()}());
                    ${buildCodeRequest.codeClassNameDTO.getDtoObjectName()}.setCreateTime(${buildCodeRequest.codeClassNameDTO.getDomainObjectName()}.getCreateTime());
                    ${buildCodeRequest.codeClassNameDTO.getDtoObjectName()}.setUpdateTime(${buildCodeRequest.codeClassNameDTO.getDomainObjectName()}.getUpdateTime());
                }
            }

            if (!updateList.isEmpty()) {
                List<${buildCodeRequest.codeClassNameDTO.getDomainClassName()}> updateListOfDomain = new ArrayList<>();
                for (${buildCodeRequest.codeClassNameDTO.getDtoClassName()} ${buildCodeRequest.codeClassNameDTO.getDtoObjectName()} : updateList) {
                    ${buildCodeRequest.codeClassNameDTO.getDomainClassName()} ${buildCodeRequest.codeClassNameDTO.getDomainObjectName()} = new ${buildCodeRequest.codeClassNameDTO.getDomainClassName()}();
                    BeanUtils.copyProperties(${buildCodeRequest.codeClassNameDTO.getDtoObjectName()}, ${buildCodeRequest.codeClassNameDTO.getDomainObjectName()});
                    updateListOfDomain.add(${buildCodeRequest.codeClassNameDTO.getDomainObjectName()});
                }
                List<${buildCodeRequest.codeClassNameDTO.getDomainClassName()}> updateRecords = ${buildCodeRequest.codeClassNameDTO.getServiceObjectName()}.${buildCodeRequest.codeMethodDTO.batchUpdateMethod}(updateListOfDomain);
                Map<Integer, ${buildCodeRequest.codeClassNameDTO.getDomainClassName()}> updateMap = new HashMap<>();
                for (${buildCodeRequest.codeClassNameDTO.getDomainClassName()} ${buildCodeRequest.codeClassNameDTO.getDomainObjectName()} : updateRecords) {
                    updateMap.put(${buildCodeRequest.codeClassNameDTO.getDomainObjectName()}.${buildCodeRequest.primaryAttributeDTO.javaAttribute.getAttributeGetMethodName()}(), ${buildCodeRequest.codeClassNameDTO.getDomainObjectName()});
                }
                for (${buildCodeRequest.codeClassNameDTO.getDtoClassName()} ${buildCodeRequest.codeClassNameDTO.getDtoObjectName()} : updateList) {
                    ${buildCodeRequest.codeClassNameDTO.getDomainClassName()} ${buildCodeRequest.codeClassNameDTO.getDomainObjectName()} = updateMap.get(${buildCodeRequest.codeClassNameDTO.getDtoObjectName()}.${buildCodeRequest.primaryAttributeDTO.javaAttribute.getAttributeGetMethodName()}());
                    ${buildCodeRequest.codeClassNameDTO.getDtoObjectName()}.setUpdateTime(${buildCodeRequest.codeClassNameDTO.getDomainObjectName()}.getUpdateTime());
                }
            }
        } catch (Exception e) {
            logger.error(ServiceExceptionHelper.getExceptionInfo(e));
            resultDO.setSuccess(false);
            resultDO.setMessage(e.getMessage());
        }
        return resultDO;
    }

    @Override
    public ResultDO<Integer> ${buildCodeRequest.codeMethodDTO.batchDeleteMethod}(List<Integer> ${buildCodeRequest.primaryAttributeDTO.javaAttribute.attributeName}List) {
        ResultDO<Integer> resultDO = new ResultDO<>();
        List<${buildCodeRequest.codeClassNameDTO.getDomainClassName()}> list = new ArrayList<>();
        for (Integer primaryKey : ${buildCodeRequest.primaryAttributeDTO.javaAttribute.attributeName}List) {
            ${buildCodeRequest.codeClassNameDTO.getDomainClassName()} ${buildCodeRequest.codeClassNameDTO.getDomainObjectName()} = new ${buildCodeRequest.codeClassNameDTO.getDomainClassName()}();
            ${buildCodeRequest.codeClassNameDTO.getDomainObjectName()}.set${buildCodeRequest.codeClassNameDTO.getJavaAttributeName()}Id(primaryKey);
            //${buildCodeRequest.codeClassNameDTO.getDomainObjectName()}.setIsDelete("Y");
            list.add(${buildCodeRequest.codeClassNameDTO.getDomainObjectName()});
        }
        int number = ${buildCodeRequest.codeClassNameDTO.getServiceObjectName()}.${buildCodeRequest.codeMethodDTO.batchUpdateMethod}(list).size();
        resultDO.setDomain(number);
        return resultDO;
    }

}
